package com.ts.utils.EGL

import android.R.attr
import android.opengl.EGL14.EGL_ALPHA_SIZE
import android.opengl.EGL14.EGL_BLUE_SIZE
import android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION
import android.opengl.EGL14.EGL_DEFAULT_DISPLAY
import android.opengl.EGL14.EGL_DEPTH_SIZE
import android.opengl.EGL14.EGL_DRAW
import android.opengl.EGL14.EGL_GREEN_SIZE
import android.opengl.EGL14.EGL_HEIGHT
import android.opengl.EGL14.EGL_NONE
import android.opengl.EGL14.EGL_NO_CONTEXT
import android.opengl.EGL14.EGL_NO_DISPLAY
import android.opengl.EGL14.EGL_NO_SURFACE
import android.opengl.EGL14.EGL_OPENGL_ES2_BIT
import android.opengl.EGL14.EGL_RED_SIZE
import android.opengl.EGL14.EGL_RENDERABLE_TYPE
import android.opengl.EGL14.EGL_STENCIL_SIZE
import android.opengl.EGL14.EGL_SUCCESS
import android.opengl.EGL14.EGL_WIDTH
import android.opengl.EGL14.eglChooseConfig
import android.opengl.EGL14.eglCreateContext
import android.opengl.EGL14.eglCreatePbufferSurface
import android.opengl.EGL14.eglCreateWindowSurface
import android.opengl.EGL14.eglDestroyContext
import android.opengl.EGL14.eglDestroySurface
import android.opengl.EGL14.eglGetCurrentContext
import android.opengl.EGL14.eglGetCurrentSurface
import android.opengl.EGL14.eglGetDisplay
import android.opengl.EGL14.eglGetError
import android.opengl.EGL14.eglInitialize
import android.opengl.EGL14.eglMakeCurrent
import android.opengl.EGL14.eglQueryContext
import android.opengl.EGL14.eglQuerySurface
import android.opengl.EGL14.eglReleaseThread
import android.opengl.EGL14.eglSwapBuffers
import android.opengl.EGL14.eglTerminate
import android.opengl.EGLConfig
import android.opengl.EGLContext
import android.opengl.EGLExt.EGL_OPENGL_ES3_BIT_KHR
import android.opengl.EGLExt.EGL_RECORDABLE_ANDROID
import android.opengl.EGLSurface
import android.util.Log
import android.view.Surface


var FLAG_RECORDABLE=1;
val FLAG_TRY_GLES3=2;
class EGLCore:ICore {
    var mEGLDisplay: android.opengl.EGLDisplay=EGL_NO_DISPLAY
    var major=IntArray(1)
    var minor=IntArray(1)



    var mEGLConfig:EGLConfig?= null
    var mEGLContext: EGLContext= EGL_NO_CONTEXT;
    var mGlVersion=3;
    constructor(sharContext: EGLContext, flags:Int){
         init(sharContext,flags);
    }

    constructor(){
        init(null,0);
    }

    override fun init(sharedContext: EGLContext?, flags: Int):Boolean {

        mEGLDisplay=eglGetDisplay(EGL_DEFAULT_DISPLAY)
        if (mEGLDisplay== EGL_NO_DISPLAY){
            return false;
        }

        if (!eglInitialize(mEGLDisplay,major,0,minor,0)){
            return false;
        }
        if ((flags and FLAG_TRY_GLES3)!=0){
            var config=getConfig(flags,3)
            if (config!=null){
                var attrib3_list=intArrayOf(
                    EGL_CONTEXT_CLIENT_VERSION, 3,
                    EGL_NONE
                )

                var context= eglCreateContext(mEGLDisplay,config,sharedContext, attrib3_list,0);
                if (eglGetError() == EGL_SUCCESS) {
                    mEGLConfig = config;
                    mEGLContext = context;
                    mGlVersion = 3;
                }
            }
        }

        if (mEGLContext==EGL_NO_CONTEXT){
            val config = getConfig(flags, 2)
            val attrib2_list = intArrayOf(
                EGL_CONTEXT_CLIENT_VERSION, 2,
                EGL_NONE
            )

            val context = eglCreateContext(
                mEGLDisplay, config,
                sharedContext, attrib2_list,0
            )

            if (eglGetError() == EGL_SUCCESS) {
                mEGLConfig = config;
                mEGLContext = context;
                mGlVersion = 2;
            }
        }


        //eglPresentationTimeANDROID

        val values= intArrayOf(1)

        eglQueryContext(mEGLDisplay,mEGLContext,
            EGL_CONTEXT_CLIENT_VERSION,
            values,0);

        Log.e(TAG,"current version "+values[0])
        return true;
    }

    private  val TAG = "EGLCore"
    override fun getConfig(flags: Int, version: Int): EGLConfig? {
        var renderableType= EGL_OPENGL_ES2_BIT;
        if (version>=3){
            renderableType = renderableType or EGL_OPENGL_ES3_BIT_KHR;
        }

        val attribList = intArrayOf(
            EGL_RED_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE, 8,
            EGL_ALPHA_SIZE, 8,
            EGL_DEPTH_SIZE, 16,
            EGL_STENCIL_SIZE, 8,
            EGL_RENDERABLE_TYPE, renderableType,
            EGL_NONE, 0,  // placeholder for recordable [@-3]
            EGL_NONE
        )
        if ((flags and FLAG_RECORDABLE) != 0) {
            attribList[attribList.size - 3] = EGL_RECORDABLE_ANDROID;
            attribList[attribList.size - 2] = 1;
        }

        var configs= arrayOfNulls<EGLConfig>(1)

        var numConfigs=IntArray(1)

        if (!eglChooseConfig(mEGLDisplay,attribList,0,configs,0,configs.size,numConfigs,0)){
            return null;
        }

        return configs[0];

    }


    override fun release() {
        if (mEGLDisplay != EGL_NO_DISPLAY) {
            eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
            eglDestroyContext(mEGLDisplay, mEGLContext);
            eglReleaseThread();
            eglTerminate(mEGLDisplay);
        }

        mEGLDisplay = EGL_NO_DISPLAY;
        mEGLContext = EGL_NO_CONTEXT;
        mEGLConfig = null;
    }

    override fun getEGLContext(): EGLContext {
        return mEGLContext;
    }

    override fun releaseSurface(eglSurface: EGLSurface) {
        eglDestroySurface(mEGLDisplay,eglSurface)
    }

    override fun createWindowsSurface(surface: Surface): EGLSurface? {
        val surfaceAttribs= intArrayOf(1)
        val eglSurface: EGLSurface =
            eglCreateWindowSurface(mEGLDisplay,mEGLConfig,surface,surfaceAttribs,0)
                ?: return null

        return eglSurface
    }

    override fun createOffscreenSurface(width: Int, height: Int):EGLSurface? {
        val surfaceAttribs = intArrayOf(
            EGL_WIDTH, attr.width,
            EGL_HEIGHT, attr.height,
            EGL_NONE
        )

        var eglSurface= eglCreatePbufferSurface(mEGLDisplay,mEGLConfig,surfaceAttribs,0)
        if (eglSurface==null){
            return null
        }

        return eglSurface;
    }

    override fun makeCurrent(eglSurface: EGLSurface) {

        if (mEGLDisplay== EGL_NO_DISPLAY){
            Log.e(TAG,"Note: makeCurrent w/o display.\n")
        }
        if (!eglMakeCurrent(mEGLDisplay,eglSurface,eglSurface,mEGLContext)){

        }
    }

    override fun makeCurrent(drawSurface: EGLSurface, readSurface: EGLSurface) {
        if (mEGLDisplay == EGL_NO_DISPLAY) {
            Log.e(TAG, "Note: makeCurrent w/o display.\n")
        }
        if (!eglMakeCurrent(mEGLDisplay, drawSurface, readSurface, mEGLContext)) {

        }
    }

    override fun makeNothingCurrent() {
        if (!eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
            // TODO 抛出异常
        }
    }

    override fun swapBuffers(eglSurface: EGLSurface): Boolean {
        return eglSwapBuffers(mEGLDisplay, eglSurface);
    }

    override fun setPresentationTime(eglSurface: EGLSurface, nsecs: Long) {

    }

    override fun isCurrent(eglSurface: EGLSurface): Boolean {
        return mEGLContext == eglGetCurrentContext() &&
                eglSurface == eglGetCurrentSurface(EGL_DRAW);
    }

    override fun querySurface(eglSurface: EGLSurface?, what: Int): Int {
        var value=IntArray(1)
        eglQuerySurface(mEGLDisplay, eglSurface, what, value,0);
        return value[0];
    }

    override fun checkEglError() {
        var error: Int
        if ((eglGetError().also { error = it }) != EGL_SUCCESS) {
            // TODO 抛出异常

        }
    }

}